#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

int nr = 0;
int nw = 0;
int valor = 0;

void* readerf();
void* writerf();

sem_t semWrite;
sem_t semRead;

struct monitor {
  
  int nr;
  int nw;
  //pthread_cond_t oktoread;
  //pthread_cond_t oktowrite;
  //pthread_mutex_t mutex;
  
  
  void request_read() {
    while(nw >0) sem_wait(&semRead);
    nr = nr + 1;
  }
  
  void release_read() {
    nr = nr -1;
    if (nr == 0) sem_post(&semWrite);
  }
  
  void request_write() {
    while (nr >0 || nw > 0) sem_wait(&semWrite);
    nw = nw + 1;
  }
  
  void release_write() {
    nw = nw -1;
    sem_post(&semWrite);
    sem_post(&semRead);
  }
  
  
}

int main(int argc, char *argv[])
{
      int i,j;
      int n,m; // Numero de Readers e Writers, respectivamente
      n = *argv[argc-2]-48;
      m = *argv[argc-1]-48;
      
      pthread_t reader[n]; // threads reader
      pthread_t writer[m]; // threads writer
     
      sem_init(&semRead,0,1);
      sem_init(&semWrite,0,1);
      
      monitor monitor;
      
      for (j = 0; j < m; j++)
	{
	  if(pthread_create(&writer[j], 0, writerf, NULL))
	    {
	      perror("Escritor nao criado!");
	      exit(1);							
	    }
	}
	
      for (i = 0; i < n; i++)
	{
	  if(pthread_create(&reader[i], 0, readerf, NULL))
	    { 
	      perror("Leitor nao criado!");
	      exit(1);							
	    }
	}
       

      
      for (i = 0; i < n; i++)
	{
	  pthread_join(reader[i], NULL);
	}
      
      for (j = 0; j < m; j++)
	{
	  pthread_join(writer[j], NULL);
	}
    
     

      pthread_exit(NULL);
      return EXIT_SUCCESS;
}

void* readerf()			
{
    
    monitor.request_read();
    nr = nr + 1;

    printf("Leitor esta lendo %d... (%d w - %d r)\n",valor,nw,nr);
    
    if(rand()%1) sleep(1);
    
  
    nr = nr - 1;
    
    printf("Leitor leu \n"); 
    monitor.release_read();
    return 0;
}

void* writerf()		
{
    monitor.request_write();
    
    nw = nw + 1;
    
    valor = (rand()%100)+1;
    printf("Escritor escreveu %d... (%d w - %d r)\n",valor,nw,nr);
    sleep(rand()%5);  
    nw = nw - 1;
    
    monitor.release_write();

    return 0;
}

